﻿using DotPowerJob.Hosted;
using DotPowerJob.Models;
using DotPowerJob.Responses;
using DotPowerJob.TaskExecutors;
using Flurl;
using Flurl.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;

namespace DotPowerJob.Extensions
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddPowerJobExecutor(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddLogging();
            services.AddOptions();
            services.Configure<PowerJobConfig>(configuration.GetSection("powerJob"))
                .CheckPowerJobService(configuration)
                .AddPowerJobExecutorServiceDependency();
            return services;
        }

        public static IServiceCollection AddXxlJobExecutor(this IServiceCollection services, Action<PowerJobConfig> configAction)
        {
            services.AddLogging();
            services.AddOptions();
            services.Configure(configAction)
                .CheckPowerJobService(configAction)
                .AddPowerJobExecutorServiceDependency();
            return services;
        }

        private static IServiceCollection AddPowerJobExecutorServiceDependency(this IServiceCollection services)
        {
            services.TryAddSingleton<IJobHandlerFactory, DefaultJobHandlerFactory>();

            services.AddSingleton<IHostedService, JobDiscoveryService>();
            services.AddSingleton<IHostedService, JobWorkerHeartbeat>();
            //services.AddSingleton<IHostedService, JobReportInstanceStatus>();

            services.AddSingleton<JobDispatcher>();

            services.AddSingleton<DefaultJobHandlerFactory>();
            services.AddSingleton<PowerJobRestfulServiceHandler>();
            services.AddSingleton<ITaskExecutor, BeanTaskExecutor>();
            return services;
        }

        /// <summary>
        /// 校验 App 是否已在 server 端注册
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        /// <exception cref="KeyNotFoundException"></exception>
        private static IServiceCollection CheckPowerJobService(this IServiceCollection services, IConfiguration configuration)
        {
            var config = new PowerJobConfig();
            configuration.GetSection("powerJob").Bind(config);
            var result = config.ServiceAddresses.AppendPathSegment("server/assert")
                .SetQueryParam("appName", config.AppName)
                .GetJsonAsync<AssertResponse>()
                .Result;
            if (result == null)
            {
                throw new Exception("Request PowerJob Service Faild");
            }
            else if (!result.Success)
            {
                throw new Exception(result.Message);
            }
            PowerJobCache.AppId = result.Data.Value;

            return services;
        }

        /// <summary>
        /// 校验 App 是否已在 server 端注册
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        /// <exception cref="KeyNotFoundException"></exception>
        private static IServiceCollection CheckPowerJobService(this IServiceCollection services, Action<PowerJobConfig> configAction)
        {
            var config = new PowerJobConfig();
            configAction.Invoke(config);
            var result = config.ServiceAddresses.AppendPathSegment("server/assert")
                .SetQueryParam("appName", config.AppName)
                .GetJsonAsync<AssertResponse>()
                .Result;
            if (result == null)
            {
                throw new Exception("Request PowerJob Service Faild");
            }
            else if (!result.Success)
            {
                throw new Exception(result.Message);
            }
            PowerJobCache.AppId = result.Data.Value;

            return services;
        }
    }
}
